#include "GraphicsModule.h"

GraphicsModule::GraphicsModule(void)
{
}

GraphicsModule::~GraphicsModule(void)
{
	if (p_Device != NULL)
	{
		p_Device->Release();
	}
}

bool GraphicsModule::initGraphics(HWND han_Window)
{	
	p_Device = InitializeDevice(han_Window);
	if (p_Device != NULL)
	{
		return true;
	}
	return false;
}

LPDIRECT3DDEVICE9 GraphicsModule::InitializeDevice(HWND han_WindowToBindTo)
{
	LPDIRECT3D9 p_dx_Object;
	LPDIRECT3DDEVICE9 p_dx_Device;

	p_dx_Object = Direct3DCreate9(D3D_SDK_VERSION);
	if (p_dx_Object == NULL)
	{
		MessageBox(han_WindowToBindTo, L"DirectX Runtime library not installed!", L"InitializeDevice()",MB_OK);
		p_dx_Object->Release();
		return NULL;
	}

	D3DCAPS9 caps;
	int max_tex_size;
	SHOW_ERROR_MSG(p_dx_Object->GetDeviceCaps(D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, &caps), L"Get caps failed");
	max_tex_size = caps.MaxTextureWidth;

	if (caps.NumSimultaneousRTs < 3)
	{
		MessageBox(han_WindowToBindTo, L"Warning no support for multiple MRTs switching to phong lighting", L"InitializeDevice()" ,MB_OK);
		TextureManager::SUPPORT_MRT = false;
	}

	if (max_tex_size < 128)
	{
		MessageBox(han_WindowToBindTo, L"Texture size is too small", L"InitializeDevice()" ,MB_OK);
		p_dx_Object->Release();
		return NULL;
	}

	UINT maxBBufferSize = min(BBUF_HEIGHT, BBUF_WIDTH);
	while (max_tex_size < TextureManager::TEXTURE_SIZE || maxBBufferSize < TextureManager::TEXTURE_SIZE)
	{
		TextureManager::TEXTURE_SIZE /= 2;
	}
	while (max_tex_size < TextureManager::SHADOW_MAP_SIZE || maxBBufferSize < TextureManager::SHADOW_MAP_SIZE)
	{
		TextureManager::SHADOW_MAP_SIZE /= 2;
	}

	HRESULT hr;
	D3DDISPLAYMODE mode;
	p_dx_Object->GetAdapterDisplayMode(D3DADAPTER_DEFAULT, &mode);

	hr = p_dx_Object->CheckDeviceType(D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, mode.Format, D3DFMT_A8R8G8B8, false);
	if(FAILED(hr))
	{
		MessageBox(han_WindowToBindTo, L"Warning your card does not support required D3DFMT_A8R8G8B8", L"InitializeDevice()" ,MB_OK);
	}
	// Most important part for deferred rendering so let's try to get at least something
	hr = p_dx_Object->CheckDeviceFormat(D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, mode.Format,
		D3DUSAGE_RENDERTARGET, D3DRTYPE_SURFACE, D3DFMT_R32F);
	if(FAILED(hr))
	{
		MessageBox(han_WindowToBindTo, L"Warning your card does not support the required D3DFMT_R32F switching to lower quality.", L"InitializeDevice()" ,MB_OK);
		hr = p_dx_Object->CheckDeviceFormat(D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, mode.Format,
			D3DUSAGE_RENDERTARGET, D3DRTYPE_SURFACE, D3DFMT_A2R10G10B10);
		if(FAILED(hr))
		{
			MessageBox(han_WindowToBindTo, L"Warning your card does not support D3DFMT_A2R10G10B10 trying again with D3DFMT_A8R8G8B8.", L"InitializeDevice()" ,MB_OK);
			hr = p_dx_Object->CheckDeviceFormat(D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, mode.Format,
				D3DUSAGE_RENDERTARGET, D3DRTYPE_SURFACE, D3DFMT_A8R8G8B8);
			if(FAILED(hr))
			{
				MessageBox(han_WindowToBindTo, L"Warning could not create depth RT.", L"InitializeDevice()" ,MB_OK);
				p_dx_Object->Release();
				return NULL;
			}
		}
	}

	hr = p_dx_Object->CheckDeviceFormat(D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL,
		mode.Format,
		D3DUSAGE_RENDERTARGET,
		D3DRTYPE_SURFACE,
		D3DFMT_A8R8G8B8);
	if(FAILED(hr))
	{
		MessageBox(han_WindowToBindTo, L"Warning your card does not support the required D3DFMT_A8R8G8B8 render target.", L"InitializeDevice()" ,MB_OK);		
	}

	hr = p_dx_Object->CheckDeviceFormat(D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL,
		mode.Format,
		D3DUSAGE_DEPTHSTENCIL,
		D3DRTYPE_SURFACE,
		D3DFMT_D24S8);
	if(FAILED(hr))
	{
		MessageBox(han_WindowToBindTo, L"Warning your card does not support the required D3DFMT_D24S8 stencil format.", L"InitializeDevice()" ,MB_OK);		
	}

	D3DPRESENT_PARAMETERS d3dpp;
	ZeroMemory(&d3dpp, sizeof(d3dpp));
	d3dpp.BackBufferWidth = BBUF_WIDTH;
	d3dpp.BackBufferHeight = BBUF_HEIGHT;
	d3dpp.BackBufferFormat = D3DFMT_A8R8G8B8; //pixel format
	d3dpp.BackBufferCount = 1;
	d3dpp.MultiSampleType = D3DMULTISAMPLE_NONE;
	d3dpp.MultiSampleQuality = 0;
	d3dpp.SwapEffect = D3DSWAPEFFECT_DISCARD;
	d3dpp.hDeviceWindow = han_WindowToBindTo;
	d3dpp.Windowed = true;
	d3dpp.EnableAutoDepthStencil = true;
	d3dpp.AutoDepthStencilFormat = D3DFMT_D24S8; // depth format
	d3dpp.Flags = 0;
	d3dpp.FullScreen_RefreshRateInHz = D3DPRESENT_RATE_DEFAULT;
	d3dpp.PresentationInterval = D3DPRESENT_INTERVAL_ONE;

	if (FAILED(p_dx_Object->CreateDevice(D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, han_WindowToBindTo,D3DCREATE_HARDWARE_VERTEXPROCESSING, &d3dpp, &p_dx_Device)))
	{
		if (FAILED(p_dx_Object->CreateDevice(D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, han_WindowToBindTo, D3DCREATE_SOFTWARE_VERTEXPROCESSING, &d3dpp, &p_dx_Device)))
		{
			if (FAILED(p_dx_Object->CreateDevice(D3DADAPTER_DEFAULT, D3DDEVTYPE_REF, han_WindowToBindTo, D3DCREATE_SOFTWARE_VERTEXPROCESSING, &d3dpp, &p_dx_Device)))
			{
				MessageBox(han_WindowToBindTo, L"Failed to create even the reference device!", L"InitializeDevice()",MB_OK);
			}
		}
	}

	p_dx_Object->Release();
	return p_dx_Device;
}


